package com.robot.merchant.service;

import com.robot.merchant.dao.StoreDao;
import com.robot.merchant.pojo.Store;
import com.robot.merchant.pojo.Tag;
import com.robot.merchant.pojo.vo.StoreWithTags;
import com.robot.merchant.util.List2PageUtil;
import entity.Point;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import util.GeoHashUtil;
import util.IdWorker;

import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.util.*;

/**
 * store服务层
 *
 * @author
 */
@Service
public class StoreService {
    @Autowired
    private StoreDao storeDao;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private IdWorker idWorker;

    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private TagService tagService;

    /**
     * 查询全部列表
     *
     * @return
     */
    public List<Store> findAll() {
        return storeDao.findAll();
    }

    /**
     * 查询全部列表并根据会员当前经纬度排序
     *
     * @param point
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAll(Point point, int page, int size) {
        List<Store> stores = storeDao.findAll();
        logger.info("point=" + point);
        //point有值才进行循环从而设置距离dis
        if (point.getLatitude() != null && point.getLongitude() != null) {
            for (Store store : stores) {
                store.setDis(point);
            }
            stores.sort(Comparator.comparing(Store::getDis));
        }

        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Store> storePage = List2PageUtil.list2Page(stores, pageable);
        logger.info(storePage.getContent().toString());
        return storePage;
    }

    /**
     * 条件查询+分页
     *
     * @param whereMap
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findSearch(Map whereMap, int page, int size) {
        Specification<Store> specification = createSpecification(whereMap);
        PageRequest pageRequest = PageRequest.of(page - 1, size);
        return storeDao.findAll(specification, pageRequest);
    }


    /**
     * 条件查询
     *
     * @param whereMap
     * @return
     */
    public List<Store> findSearch(Map whereMap) {
        Specification<Store> specification = createSpecification(whereMap);
        return storeDao.findAll(specification);
    }

    /**
     * 根据ID查询实体
     *
     * @param id
     * @return
     */
    public Store findById(String id) {
        return storeDao.findById(id).orElse(null);
    }

    /**
     * 增加
     *
     * @param store
     */
    public void add(Store store) {
        store.setStatus("1");
        store.setType("0");
        LocalDateTime now = LocalDateTime.now();
        store.setCreatedAt(now);
        store.setUpdatedAt(now);
        logger.info(store.toString());
        storeDao.save(store);
    }

    /**
     * 修改
     *
     * @param store
     */
    public void update(Store store) {
        storeDao.save(store);
    }

    /**
     * 删除
     *
     * @param id
     */
    public void deleteById(String id) {
        storeDao.deleteById(id);
    }

    /**
     * 动态条件构建
     *
     * @param searchMap
     * @return
     */
    private Specification<Store> createSpecification(Map searchMap) {
        logger.info("store's searchMap" + searchMap);
        return (Specification<Store>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            // 店铺id
            String id = "id";
            if (searchMap.get(id) != null && !"".equals(searchMap.get(id))) {
                predicateList.add(cb.like(root.get(id).as(String.class), "%" + (String) searchMap.get(id) + "%"));
            }
            // 店铺名字
            String storeName = "storeName";
            if (searchMap.get(storeName) != null && !"".equals(searchMap.get(storeName))) {
                predicateList.add(cb.like(root.get(storeName).as(String.class), "%" + (String) searchMap.get(storeName) + "%"));
            }
            // 公司id
            String companyId = "companyId";
            if (searchMap.get(companyId) != null && !"".equals(searchMap.get(companyId))) {
                predicateList.add(cb.like(root.get(companyId).as(String.class), "%" + (String) searchMap.get(companyId) + "%"));
            }
            // 代理商id
            String agentId = "agentId";
            if (searchMap.get(agentId) != null && !"".equals(searchMap.get(agentId))) {
                predicateList.add(cb.like(root.get(agentId).as(String.class), "%" + (String) searchMap.get(companyId) + "%"));
            }
            // 会员id
            String memberId = "memberId";
            if (searchMap.get(memberId) != null && !"".equals(searchMap.get(memberId))) {
                predicateList.add(cb.like(root.get(memberId).as(String.class), "%" + (String) searchMap.get(memberId) + "%"));
            }
            // 联系人
            String contact = "contact";
            if (searchMap.get(contact) != null && !"".equals(searchMap.get(contact))) {
                predicateList.add(cb.like(root.get(contact).as(String.class), "%" + (String) searchMap.get(contact) + "%"));
            }
            // 电话
            String phone = "phone";
            if (searchMap.get(phone) != null && !"".equals(searchMap.get(phone))) {
                predicateList.add(cb.like(root.get(phone).as(String.class), "%" + (String) searchMap.get(phone) + "%"));
            }
            // 邮箱
            String email = "email";
            if (searchMap.get(email) != null && !"".equals(searchMap.get(email))) {
                predicateList.add(cb.like(root.get(email).as(String.class), "%" + (String) searchMap.get(email) + "%"));
            }
            // 营业执照号码
            String businessLicense = "businessLicense";
            if (searchMap.get(businessLicense) != null && !"".equals(searchMap.get(businessLicense))) {
                predicateList.add(cb.like(root.get(businessLicense).as(String.class), "%" + (String) searchMap.get(businessLicense) + "%"));
            }
            // 经度
            String longitude = "longitude";
            if (searchMap.get(longitude) != null && !"".equals(searchMap.get(longitude))) {
                predicateList.add(cb.like(root.get(longitude).as(String.class), "%" + (String) searchMap.get(longitude) + "%"));
            }
            // 纬度
            String latitude = "latitude";
            if (searchMap.get(latitude) != null && !"".equals(searchMap.get(latitude))) {
                predicateList.add(cb.like(root.get(latitude).as(String.class), "%" + (String) searchMap.get(latitude) + "%"));
            }
            // 行业id
            String industryId = "industryId";
            if (searchMap.get(industryId) != null && !"".equals(searchMap.get(industryId))) {
                predicateList.add(cb.like(root.get(industryId).as(String.class), "%" + (String) searchMap.get(industryId) + "%"));
            }
            // 行业许可证编号
            String industryLicense = "industryLicense";
            if (searchMap.get(industryLicense) != null && !"".equals(searchMap.get(industryLicense))) {
                predicateList.add(cb.like(root.get(industryLicense).as(String.class), "%" + (String) searchMap.get(industryLicense) + "%"));
            }
            // 法人真实姓名
            String realName = "realName";
            if (searchMap.get(realName) != null && !"".equals(searchMap.get(realName))) {
                predicateList.add(cb.like(root.get(realName).as(String.class), "%" + (String) searchMap.get(realName) + "%"));
            }
            // 实名制状态 0-未实名 1-已实名 2-实名失败
            String realNameStatus = "realNameStatus";
            if (searchMap.get(realNameStatus) != null && !"".equals(searchMap.get(realNameStatus))) {
                predicateList.add(cb.like(root.get(realNameStatus).as(String.class), "%" + (String) searchMap.get(realNameStatus) + "%"));
            }
            // 法人身份证号码
            String idCard = "idCard";
            if (searchMap.get(idCard) != null && !"".equals(searchMap.get(idCard))) {
                predicateList.add(cb.like(root.get(idCard).as(String.class), "%" + (String) searchMap.get(idCard) + "%"));
            }
            // 省份
            String province = "province";
            if (searchMap.get(province) != null && !"".equals(searchMap.get(province))) {
                predicateList.add(cb.like(root.get(province).as(String.class), "%" + (String) searchMap.get(province) + "%"));
            }
            // 省份id
            String provinceId = "provinceId";
            if (searchMap.get(provinceId) != null && !"".equals(searchMap.get(provinceId))) {
                predicateList.add(cb.like(root.get(provinceId).as(String.class), "%" + (String) searchMap.get(provinceId) + "%"));
            }
            // 城市
            String city = "city";
            if (searchMap.get(city) != null && !"".equals(searchMap.get(city))) {
                predicateList.add(cb.like(root.get(city).as(String.class), "%" + (String) searchMap.get(city) + "%"));
            }
            // 城市id
            String cityId = "cityId";
            if (searchMap.get(cityId) != null && !"".equals(searchMap.get(cityId))) {
                predicateList.add(cb.like(root.get(cityId).as(String.class), "%" + (String) searchMap.get(cityId) + "%"));
            }
            // 区县
            String area = "area";
            if (searchMap.get(area) != null && !"".equals(searchMap.get(area))) {
                predicateList.add(cb.like(root.get(area).as(String.class), "%" + (String) searchMap.get(area) + "%"));
            }
            // 区县id
            String areaId = "areaId";
            if (searchMap.get(areaId) != null && !"".equals(searchMap.get(areaId))) {
                predicateList.add(cb.like(root.get(areaId).as(String.class), "%" + (String) searchMap.get(areaId) + "%"));
            }
            // 详细地址
            String address = "address";
            if (searchMap.get(address) != null && !"".equals(searchMap.get(address))) {
                predicateList.add(cb.like(root.get(address).as(String.class), "%" + (String) searchMap.get(address) + "%"));
            }
            // 微信open_id
            String openId = "openId";
            if (searchMap.get(openId) != null && !"".equals(searchMap.get(openId))) {
                predicateList.add(cb.like(root.get(openId).as(String.class), "%" + (String) searchMap.get(openId) + "%"));
            }
            // 微信union_id
            String unionId = "unionId";
            if (searchMap.get(unionId) != null && !"".equals(searchMap.get(unionId))) {
                predicateList.add(cb.like(root.get(unionId).as(String.class), "%" + (String) searchMap.get(unionId) + "%"));
            }
            // json vip1=会员折扣率 vip2=会长折扣率
            String rate = "rate";
            if (searchMap.get(rate) != null && !"".equals(searchMap.get(rate))) {
                predicateList.add(cb.like(root.get(rate).as(String.class), "%" + (String) searchMap.get(rate) + "%"));
            }
            // 推荐人id
            String recommendId = "recommendId";
            if (searchMap.get(recommendId) != null && !"".equals(searchMap.get(recommendId))) {
                predicateList.add(cb.like(root.get(recommendId).as(String.class), "%" + (String) searchMap.get(recommendId) + "%"));
            }
            // 店铺推荐语
            String recommendation = "recommendation";
            if (searchMap.get(recommendation) != null && !"".equals(searchMap.get(recommendation))) {
                predicateList.add(cb.like(root.get(recommendation).as(String.class), "%" + (String) searchMap.get(recommendation) + "%"));
            }
            // 评分 店铺所有订单的评分的均值
            String score = "score";
            if (searchMap.get(score) != null && !"".equals(searchMap.get(score))) {
                predicateList.add(cb.like(root.get(score).as(String.class), "%" + (String) searchMap.get(score) + "%"));
            }
            // 商户类型 0-充送 1-折扣
            String type = "type";
            if (searchMap.get(type) != null && !"".equals(searchMap.get(type))) {
                predicateList.add(cb.like(root.get(type).as(String.class), "%" + (String) searchMap.get(type) + "%"));
            }
            // 开户行名称
            String bankName = "bankName";
            if (searchMap.get(bankName) != null && !"".equals(searchMap.get(bankName))) {
                predicateList.add(cb.like(root.get(bankName).as(String.class), "%" + (String) searchMap.get(bankName) + "%"));
            }
            // 银行账号
            String bankAccount = "bankAccount";
            if (searchMap.get(bankAccount) != null && !"".equals(searchMap.get(bankAccount))) {
                predicateList.add(cb.like(root.get(bankAccount).as(String.class), "%" + (String) searchMap.get(bankAccount) + "%"));
            }
            // 户名
            String accountName = "accountName";
            if (searchMap.get(accountName) != null && !"".equals(searchMap.get(accountName))) {
                predicateList.add(cb.like(root.get(accountName).as(String.class), "%" + (String) searchMap.get(accountName) + "%"));
            }
            // 账户类型 0-对私 1-对公
            String accountType = "accountType";
            if (searchMap.get(accountType) != null && !"".equals(searchMap.get(accountType))) {
                predicateList.add(cb.like(root.get(accountType).as(String.class), "%" + (String) searchMap.get(accountType) + "%"));
            }
            // 0-禁用 1-启用
            String status = "status";
            if (searchMap.get(status) != null && !"".equals(searchMap.get(status))) {
                predicateList.add(cb.like(root.get(status).as(String.class), "%" + (String) searchMap.get(status) + "%"));
            }
            // 备注
            String remark = "remark";
            if (searchMap.get(remark) != null && !"".equals(searchMap.get(remark))) {
                predicateList.add(cb.like(root.get(remark).as(String.class), "%" + (String) searchMap.get(remark) + "%"));
            }
            //剔除软删除数据
            String deletedAt = "deletedAt";
            predicateList.add(cb.equal(root.get(deletedAt), cb.nullLiteral(Date.class)));

            return cb.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };
    }


    /**
     * 检查商家
     *
     * @param storeInDb
     * @return
     */
    public String checkStore(Store storeInDb) {
        logger.info("storeInDb=" + storeInDb);
        if (storeInDb == null) {
            return "商家不存在";
        }
        if (storeInDb.getDeletedAt() != null) {
            return "商家被删除";
        }
        /**
         * store表status 0-禁用 1-启用
         */
        String storeStatusEnable = "1";
        if (!storeStatusEnable.equals(storeInDb.getStatus())) {
            return "商家状态异常";
        }
        return "";
    }

    /**
     * 通过phone查找store
     *
     * @param phone
     * @return
     */
    public Store findByPhone(String phone) {
        return storeDao.findByPhone(phone);
    }

    /**
     * 根据halfGeoHash查找店铺
     *
     * @param halfGeoHash 半地理编码
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByHalfGeoHash(String halfGeoHash, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findStoresByHalfGeoHashAndStatusAndDeletedAtIsNull(halfGeoHash, "1", pageable);
    }

    /**
     * 根据geoHash查找店铺
     *
     * @param geoHash 全地理编码
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByGeoHash(String geoHash, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findStoresByGeoHash(geoHash, "1", pageable);
    }

    /**
     * 通过id和companyId查询店铺
     *
     * @param id
     * @param companyId
     * @return
     */
    public Store findByIdAndCompanyId(String id, String companyId) {
        return storeDao.findByIdAndCompanyId(id, companyId);
    }

    /**
     * (关键词搜索)根据storeName,recommendation,status的店铺
     *
     * @param keywords
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByKeywordsAndStatusAndDeletedAtIsNull(Point point, String keywords, int page, int size) {
        List<Store> stores = storeDao.findStoresByKeywordsAndStatusAndDeletedAtIsNull(keywords, keywords, "1");
        //如果point不为空则算距离并排序
        if(point!=null){
            GeoHashUtil geoHashUtil = new GeoHashUtil();
            String geoHash = geoHashUtil.encode(Double.parseDouble(point.getLatitude()), Double.parseDouble(point.getLongitude()));
            String halfGeoHash = geoHash.substring(0, 5);
            logger.info("halfGeoHash=" + halfGeoHash);
            for (Store store : stores) {
                store.setDis(point);
            }
            stores.sort(Comparator.comparing(Store::getDis));
        }
        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Store> storePage = List2PageUtil.list2Page(stores, pageable);
        logger.info(storePage.getContent().toString());
        return storePage;
    }

    /**
     * 通过id和agentId查询店铺
     *
     * @param id
     * @param agentId
     * @return
     */
    public Store findByIdAndAgentId(String id, String agentId) {
        return storeDao.findByIdAndAgentId(id, agentId);
    }

    /**
     * 通过agentId查询店铺列表
     *
     * @param agentId
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByAgentIdOrderByCreatedAtDesc(String agentId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByAgentIdOrderByCreatedAtDesc(agentId, pageable);

    }


    /**
     * agent根据agentId查找昨天开张的店铺
     *
     * @param agentId
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByAgentIdAndYesterday(String agentId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findStoresByAgentIdAndYesterday(agentId, pageable);

    }

    /**
     * agent根据agentId查找最近7日开张的店铺
     *
     * @param agentId
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByAgentIdAndWeek(String agentId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findStoresByAgentIdAndWeek(agentId, pageable);
    }

    /**
     * agent根据agentId查找总开张的店铺
     *
     * @param agentId
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findStoresByAgentIdAndTotal(String agentId, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findStoresByAgentIdAndTotal(agentId, pageable);
    }

    public Store findEnableStoreById(String id) {
        Store store = storeDao.findStoreByIdAndStatus(id, "1");
        if(store!=null){
            logger.info(store.toString());
            return store;
        }else{
            return null;
        }
    }


    /**
     * 查找今日入驻商家
     *
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByToday(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByToday(pageable);
    }

    /**
     * 查找昨日入驻商家
     *
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByYesterday(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByYesterday(pageable);
    }

    /**
     * 查找最近7日入驻商家
     *
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByWeek(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByWeek(pageable);
    }

    /**
     * 根据时间段查找总入驻商家
     *
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByBetweenAnd(String startTime, String endTime, int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByBetweenAnd(startTime, endTime, pageable);
    }

    /**
     * 查找总入驻商家
     *
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findAllByTotal(int page, int size) {
        Pageable pageable = PageRequest.of(page - 1, size);
        return storeDao.findAllByTotal(pageable);
    }

    public Page<Store> findByPoint(Point point, int page, int size) {
        GeoHashUtil geoHashUtil = new GeoHashUtil();
        String halfGeoHash = geoHashUtil.halfGeoHash(Double.parseDouble(point.getLatitude()), Double.parseDouble(point.getLongitude()));

        logger.info("halfGeoHash=" + halfGeoHash);

        List<Store> stores = storeDao.findByHalfGeoHash(halfGeoHash);

        for (Store store : stores) {
            store.setDis(point);
        }

        stores.sort(Comparator.comparing(Store::getDis));

        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Store> storePage = List2PageUtil.list2Page(stores, pageable);
        logger.info(storePage.getContent().toString());
        return storePage;
    }


    /**
     * 根据ID查询行业下的店铺列表
     *
     * @param point
     * @param industryId
     * @param page
     * @param size
     * @return
     */
    public Page<Store> findByPointAndIndustryId(Point point, String industryId, int page, int size) {
        List<Store> stores=null;
        if(point==null|| Objects.equals(point.getLatitude(), "null") || Objects.equals(point.getLongitude(), "")){
            stores=storeDao.findByIndustryIdAndDeletedAtIsNull(industryId);
        }else{
            GeoHashUtil geoHashUtil = new GeoHashUtil();
            String halfGeoHash = geoHashUtil.halfGeoHash(Double.parseDouble(point.getLatitude()), Double.parseDouble(point.getLongitude()));
            logger.info("halfGeoHash=" + halfGeoHash);
            stores = storeDao.findByHalfGeoHashAndIndustryId(halfGeoHash, industryId);
            for (Store store : stores) {
                store.setDis(point);
            }
            stores.sort(Comparator.comparing(Store::getDis));
        }

        Pageable pageable = PageRequest.of(page - 1, size);
        Page<Store> storePage = List2PageUtil.list2Page(stores, pageable);
        logger.info(storePage.getContent().toString());
        return storePage;
    }


    public List<Store> getStoriesByIndustryId(String industryId) {
        return storeDao.findByIndustryIdAndDeletedAtIsNull(industryId);
    }

    public List<StoreWithTags> getStoriesWithTags(List<Store> stories) {
        ArrayList<StoreWithTags> storeWithTagsArrayList = new ArrayList<>();
        for (Store store : stories) {
            List<Tag> tags = tagService.findTagsByStoreId(store.getId());
            StoreWithTags storeWithTags = new StoreWithTags(store, tags);
            storeWithTagsArrayList.add(storeWithTags);
        }
        return storeWithTagsArrayList;
    }


}
